package org.beyondhc.lessons.observer;

import java.util.EventListener;
import java.util.logging.Logger;

import javax.swing.event.EventListenerList;

import junit.framework.TestCase;

import org.beyondhc.test.LogMsgCaptor;
import org.junit.Test;

/**
 * 
 * Shows how to prepare for the possible future need of observer pattern.
 * 
 * @author Jaana Kulmala
 * 
 */
public class EventListenerListObserver extends TestCase {

    public class Koala {
        private final EventListenerList observers = new EventListenerList();

        public void addKoalaListener(final KoalaObserver observer) {
            observers.add(KoalaObserver.class, observer);
        }

        public void removeKoalaListener(final KoalaObserver observer) {
            observers.remove(KoalaObserver.class, observer);
        }

        public void setHungry(final boolean isHungry) {
            final KoalaEvent event = new KoalaEvent(isHungry);
            fireKoalaChanged(event);
        }

        private void fireKoalaChanged(final KoalaEvent event) {
            // Guaranteed to return a non-null array
            final Object[] listeners = observers.getListenerList();
            // Process the listeners last to first, notifying
            // those that are interested in this event
            for (int i = listeners.length - 2; i >= 0; i -= 2) {
                if (listeners[i] == KoalaObserver.class) {

                    ((KoalaObserver) listeners[i + 1]).koalaUpdate(this, event);
                }
            }
        }

        @Override
        public String toString() {
            return "koala";
        }
    }

    public class KoalaEvent {

        private final boolean hungry;

        public KoalaEvent(final boolean isHungry) {
            this.hungry = isHungry;
        }

        public boolean isHungry() {
            return hungry;
        }

    }

    public interface KoalaObserver extends EventListener {
        void koalaUpdate(Koala koala, KoalaEvent change);
    }

    public class ZooKeeper implements KoalaObserver {

        @Override
        public void koalaUpdate(final Koala koala, final KoalaEvent change) {
            if (change.isHungry()) {
                LOGGER.info("Oh, the " + koala
                        + " is hungry. It needs some eucalyptus.");
            }
        }

    }

    private static final transient Logger LOGGER = Logger
            .getLogger(EventListenerListObserver.class.getName());

    /**
     * Here is the degenerated observer in action.
     */
    @Test
    public void testKoalaGetsFood() {
        final LogMsgCaptor logMsgCaptor = new LogMsgCaptor(LOGGER);
        final Koala koala = new Koala();
        final ZooKeeper zooKeeper = new ZooKeeper();

        koala.addKoalaListener(zooKeeper);
        koala.setHungry(true);
        assertEquals("The zookeeper should get notification",
                "Oh, the koala is hungry. It needs some eucalyptus.",
                logMsgCaptor.getMsg());
    }

}
